package com.niiwoo.civet.account.service.local.openAccount;

import com.niiwoo.civet.account.constant.AccountRegisterErrorCode;
import com.niiwoo.civet.account.dao.entity.*;
import com.niiwoo.civet.account.dto.common.LanMaoGatewayRequestDTO;
import com.niiwoo.civet.account.dto.request.CreateRegisterOrderRequestDTO;
import com.niiwoo.civet.account.dto.request.UpdateActivateAccountRequestDTO;
import com.niiwoo.civet.account.dto.response.UpdateActivateAccountOrderResponseDTO;
import com.niiwoo.civet.account.enums.AccountActiveEnum;
import com.niiwoo.civet.account.enums.AccountTypeEnum;
import com.niiwoo.civet.account.enums.ActivateAccountOrderStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountRecordStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountWayEnum;
import com.niiwoo.civet.account.service.local.AccountCompanyService;
import com.niiwoo.civet.account.service.local.AccountPersonService;
import com.niiwoo.civet.account.service.local.ActivateAccountOrderService;
import com.niiwoo.civet.account.service.local.BankCardService;
import com.niiwoo.civet.account.service.local.OpenAccountRecordService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.lanmao.component.LanMaoGatewayService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.UserAuthorizationEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.response.QueryUserInformationResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import org.springframework.beans.factory.annotation.Autowired;

//@Component
public class ActivateOpenAccountService extends AbstractOpenAccountService<UpdateActivateAccountRequestDTO, UpdateActivateAccountOrderResponseDTO> {

    private static final List<UserRoleEnum> SUPPORT_ROLE_LIST = Arrays.asList(UserRoleEnum.INVESTOR, UserRoleEnum.BORROWERS, UserRoleEnum.GUARANTEECORP);

    private static final List<OpenAccountWayEnum> SUPPORT_WAY_LIST = Arrays.asList(OpenAccountWayEnum.ACTIVATE, OpenAccountWayEnum.R360_ACTIVATE, OpenAccountWayEnum.ENTERPRISE_ACTIVATE);

    @Autowired
    OpenAccountTemplate openAccountTemplate;

    @Autowired
    ActivateAccountOrderService activateAccountOrderService;

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    OpenAccountRecordService openAccountRecordService;

    @Autowired
    BankCardService bankCardService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Autowired
    AccountCompanyService accountCompanyService;

    @Autowired
    AccountPersonService accountPersonService;

    @Autowired
    LanMaoSequence lanMaoSequence;

    @Autowired
    LanMaoGatewayService lanMaoGatewayService;

    @Override
    protected LanMaoGatewayRequestDTO internalCreateOrder(CreateRegisterOrderRequestDTO requestDTO) {
        // 查询开户记录
        List<OpenAccountRecord> recordList = Optional.ofNullable(openAccountRecordService.getByUserId(requestDTO.getUserId())).orElse(Collections.EMPTY_LIST);

        Optional<OpenAccountRecord> currentRoleRecordOpt = recordList.stream()
                .filter(r -> Objects.equals(r.getAccountRole(), Integer.valueOf(requestDTO.getAccountRole().getValue()).byteValue()))
                .findFirst();
        // 当前角色开户记录
        currentRoleRecordOpt.ifPresent(r -> {
            switch (OpenAccountRecordStatusEnum.of(r.getStatus())) {
                case AUDITING:
                    throw new BizException(AccountRegisterErrorCode.ACCOUNT_AUDITING);
                case SUCCESS:
                    throw new BizException(AccountRegisterErrorCode.HAS_REGISTERED_ACCOUNT);
            }
        });
        // 其他角色开户记录
        recordList.stream()
                .filter(r -> !Objects.equals(r.getAccountRole(), Integer.valueOf(requestDTO.getAccountRole().getValue()).byteValue()))
                .findFirst()
                .ifPresent(r -> {
                    switch (OpenAccountRecordStatusEnum.of(r.getStatus())) {
                        case PROCESSING:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_PROCESSING_ACCOUNT);
                        case AUDITING:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_AUDITING_ACCOUNT);
                        case AUDIT_RETURN:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_AUDIT_RETURN_ACCOUNT);
                        case SUCCESS:
                            throw new BizException(AccountRegisterErrorCode.HAS_OTHER_REGISERED_ACCOUNT);
                    }
                });
        // 是否存在待激活的角色账户
        AccountBase accountBase = Optional.ofNullable(openAccountRecordService.getAccountBase(requestDTO.getUserId(), requestDTO.getAccountRole()))
                .filter(a -> a.getImportUserActiva().equals(AccountActiveEnum.UNACTIVATED.getValue()))
                .orElseThrow(() -> new BizException(AccountRegisterErrorCode.ACCOUNT_NOT_EXISTS));
        // 获取更新或初始化开户记录
        OpenAccountRecord record = AccountEntityBuilder.buildRefreshOpenAccountRecord(currentRoleRecordOpt, () -> snowflakeIdWorker.nextId(), accountBase::getAccountNo, "", requestDTO);
        // 权限
        Set<String> authList = openAccountTemplate.getAuthSetByRole(UserRoleEnum.enumOf(accountBase.getAccountRole()));
        if (accountBase.getTender() == (byte) 1) {
            authList.add(UserAuthorizationEnum.TENDER.name());
        }
        if (accountBase.getRepayment() == (byte) 1) {
            authList.add(UserAuthorizationEnum.REPAYMENT.name());
        }
        if (accountBase.getCreditAssignment() == (byte) 1) {
            authList.add(UserAuthorizationEnum.CREDIT_ASSIGNMENT.name());
        }
        if (accountBase.getCompensatory() == (byte) 1) {
            authList.add(UserAuthorizationEnum.COMPENSATORY.name());
        }
        if (accountBase.getWithdraw() == (byte) 1) {
            authList.add(UserAuthorizationEnum.WITHDRAW.name());
        }
        if (accountBase.getRecharge() == (byte) 1) {
            authList.add(UserAuthorizationEnum.RECHARGE.name());
        }
        // 创建激活账户订单
        ActivateAccountOrder order = AccountEntityBuilder.buildInitActivateAccountOrder(snowflakeIdWorker.nextId(), lanMaoSequence.getRequestNo(), accountBase, String.join(",", authList));
        // 更新开户记录和订单
        if (!openAccountRecordService.saveRecordAndAccountOrder(currentRoleRecordOpt.isPresent(), record, () -> activateAccountOrderService.saveOrder(order))) {
            throw new BizException(AccountRegisterErrorCode.CREATE_ACCOUNT_REGISTER_ORDER_FAIL);
        }
        // 创建网关请求参数并返回
        return AccountLanMaoGatewayRequestBuilder.newActivateAccountRequest(req -> lanMaoGatewayService.activateAccount(req), order, requestDTO.getRedirectUrl());
    }

    @Override
    public UpdateActivateAccountOrderResponseDTO updateOrder(UpdateActivateAccountRequestDTO requestDTO) {
        return doUpdateOrder(
                () -> activateAccountOrderService.getByRequestNo(requestDTO.getRequestNo()),
                order -> ActivateAccountOrderStatusEnum.except(order.getStatus(), ActivateAccountOrderStatusEnum.SUCCESS),
                order -> {
                    UpdateActivateAccountOrderResponseDTO responseDTO = new UpdateActivateAccountOrderResponseDTO();
                    responseDTO.setOrderId(order.getId());
                    responseDTO.setRequestNo(order.getRequestNo());
                    responseDTO.setOrderStatus(ActivateAccountOrderStatusEnum.SUCCESS);
                    return responseDTO;
                },
                order -> openAccountRecordService.getByUserIdAndRole(order.getUserId(), UserRoleEnum.enumOf(order.getUserRole())),
                (order, record) -> {
                    UpdateActivateAccountOrderResponseDTO responseDTO = new UpdateActivateAccountOrderResponseDTO();
                    responseDTO.setOrderId(order.getId());
                    responseDTO.setRequestNo(order.getRequestNo());
                    ActivateAccountOrderStatusEnum orderStatus;
                    switch (requestDTO.getStatus()) {
                        case SUCCESS: {
                            orderStatus = updateSuccessOrder(record, order, requestDTO);
                        }
                        break;
                        case FAILURE: {
                            orderStatus = updateFailOrder(record, OpenAccountRecordStatusEnum.FAILURE, order, ActivateAccountOrderStatusEnum.FAILURE, requestDTO);
                        }
                        break;
                        default: {
                            orderStatus = ActivateAccountOrderStatusEnum.of(order.getStatus());
                        }
                    }
                    responseDTO.setOrderStatus(orderStatus);
                    return responseDTO;
                }
        );
    }

    @Override
    protected List<UserRoleEnum> getSupportRole() {
        return SUPPORT_ROLE_LIST;
    }

    @Override
    protected List<OpenAccountWayEnum> getSupportWay() {
        return SUPPORT_WAY_LIST;
    }

    private ActivateAccountOrderStatusEnum updateSuccessOrder(OpenAccountRecord record, ActivateAccountOrder order, UpdateActivateAccountRequestDTO requestDTO) {
        AccountBase oldBase = Optional.ofNullable(openAccountRecordService.getAccountBase(record.getUserId(), UserRoleEnum.enumOf(record.getAccountRole()))).orElseThrow(() -> new BizException(AccountRegisterErrorCode.ACCOUNT_NOT_EXISTS));
        BankCard preBankCard = bankCardService.getSimpleUserBankCard(record.getUserId());
        boolean isPersonal = OpenAccountWayEnum.except(record.getOpenAccountWay(), OpenAccountWayEnum.ACTIVATE, OpenAccountWayEnum.R360_ACTIVATE);
        // 投资和借款激活
        if (isPersonal) {
            return updateSuccessOrder(record, order, oldBase, preBankCard, requestDTO, response -> {
                AccountPerson person = AccountEntityBuilder.buildActivateAccountPerson(oldBase.getId(), response.getName(), privacyMasks.encryptPrivacy(response.getIdCardNo()));
                return () -> accountPersonService.update(person);
            });
        } else {
            // 企业激活
            switch (requestDTO.getAuditStatus()) {
                // 审核通过
                case PASSED: {
                    return updateSuccessOrder(record, order, oldBase, preBankCard, requestDTO, response -> {
                        AccountCompany accountCompany = AccountEntityBuilder.buildActivateAccountCompany(oldBase.getId(), response.getName(), response.getLegal(), privacyMasks.encryptPrivacy(response.getIdCardNo()), response.getIdCardType(), privacyMasks.encryptPrivacy(response.getMobile()), response.getBankLicense());
                        return () -> accountCompanyService.update(accountCompany);
                    });
                }
                // 审核退回
                case BACK:
                    return this.updateFailOrder(record, OpenAccountRecordStatusEnum.AUDIT_RETURN, order, ActivateAccountOrderStatusEnum.AUDIT_RETURN, requestDTO);
                // 审核拒绝
                case REFUSED:
                    return this.updateFailOrder(record, OpenAccountRecordStatusEnum.AUDIT_REJECT, order, ActivateAccountOrderStatusEnum.AUDIT_REJECT, requestDTO);
                // 审核中
                case AUDIT:
                    return this.updateFailOrder(record, OpenAccountRecordStatusEnum.AUDITING, order, ActivateAccountOrderStatusEnum.AUDITING, requestDTO);
            }
        }
        // 默认返回原状态
        return ActivateAccountOrderStatusEnum.of(order.getStatus());
    }

    private ActivateAccountOrderStatusEnum updateSuccessOrder(OpenAccountRecord record, ActivateAccountOrder order, AccountBase oldBase, BankCard preBankCard, UpdateActivateAccountRequestDTO requestDTO, Function<QueryUserInformationResponse, Supplier<Boolean>> f) {
        ActivateAccountOrder updateOrder = AccountEntityBuilder.buildUpdateActivateAccountOrder(order, ActivateAccountOrderStatusEnum.SUCCESS, requestDTO, text -> privacyMasks.encryptPrivacy(text));
        QueryUserInformationResponse response = openAccountTemplate.queryLanmaoAccountStatus(oldBase.getAccountNo(), lanMaoSequence.getRequestNo());
        Set<String> authSet = new HashSet<>(Arrays.asList(response.getAuthlist().split(",")));
        // 个人/企业更新函数
        Supplier<Boolean> s1 = f.apply(response);
        // 银行卡更新函数
        Supplier<Boolean> s2 = openAccountTemplate.getUpdateBankFunction(preBankCard, oldBase.getUserId(), oldBase.getId(), AccountTypeEnum.of(oldBase.getAccountType()), response.getName(), response.getIdCardNo(), response.getBankcardNo(), response.getBankcode().getCode(), response.getMobile());
        boolean isSuccess = openAccountTemplate.doHandleSuccessOrder(
                record,
                requestDTO.getGroupAccountNo(),
                () -> activateAccountOrderService.updateOrder(updateOrder),
                false,
                AccountEntityBuilder.buildActivateAccountBase(oldBase, authSet),
                s1,
                s2
        );
        return isSuccess ? ActivateAccountOrderStatusEnum.SUCCESS : ActivateAccountOrderStatusEnum.of(order.getStatus());
    }

    private ActivateAccountOrderStatusEnum updateFailOrder(OpenAccountRecord record, OpenAccountRecordStatusEnum recordStatus, ActivateAccountOrder order, ActivateAccountOrderStatusEnum orderStatus, UpdateActivateAccountRequestDTO requestDTO) {
        boolean isSuccess = openAccountTemplate.doHandleUnSuccessOrder(
                record,
                recordStatus,
                () -> activateAccountOrderService.updateOrder(AccountEntityBuilder.buildUpdateActivateAccountOrder(order, orderStatus, requestDTO, text -> privacyMasks.encryptPrivacy(text))),
                requestDTO.getErrorCode(),
                requestDTO.getErrorMessage()
        );
        return isSuccess ? orderStatus : ActivateAccountOrderStatusEnum.of(order.getStatus());

    }

}
